/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package desarrollosoft.ghce.servicio.implementaciones;

import desarrollosoft.ghce.dao.interfaces.IPrestacionDAO;
import desarrollosoft.ghce.dao.interfaces.IConsultaDAO;
import desarrollosoft.ghce.dao.interfaces.IDiagnosticoDAO;
import desarrollosoft.ghce.dao.interfaces.IElementoDAO;
import desarrollosoft.ghce.dao.interfaces.IEstudioDAO;
import desarrollosoft.ghce.dao.interfaces.IGravedadDAO;
import desarrollosoft.ghce.dao.interfaces.IImagenDAO;
import desarrollosoft.ghce.dao.interfaces.IIntervencionDAO;
import desarrollosoft.ghce.dao.interfaces.IMonodrogaDAO;
import desarrollosoft.ghce.dao.interfaces.IPlantillaDAO;
import desarrollosoft.ghce.dao.interfaces.IProfesionalDAO;
import desarrollosoft.ghce.dao.interfaces.IResultadoComponenteDAO;
import desarrollosoft.ghce.dao.interfaces.ITratamientoDAO;
import desarrollosoft.ghce.dao.interfaces.IValorNormalDAO;
import desarrollosoft.ghce.entidades.Prestacion;
import desarrollosoft.ghce.entidades.Componente;
import desarrollosoft.ghce.entidades.Consulta;
import desarrollosoft.ghce.entidades.Diagnostico;
import desarrollosoft.ghce.entidades.Elemento;
import desarrollosoft.ghce.entidades.Estudio;
import desarrollosoft.ghce.entidades.EstudioImaginologia;
import desarrollosoft.ghce.entidades.EstudioLaboratorio;
import desarrollosoft.ghce.entidades.Gravedad;
import desarrollosoft.ghce.entidades.Imagen;
import desarrollosoft.ghce.entidades.Intervencion;
import desarrollosoft.ghce.entidades.Monodroga;
import desarrollosoft.ghce.entidades.Paciente;
import desarrollosoft.ghce.entidades.Plantilla;
import desarrollosoft.ghce.entidades.Profesional;
import desarrollosoft.ghce.entidades.ResultadoComponente;
import desarrollosoft.ghce.entidades.Tratamiento;
import desarrollosoft.ghce.entidades.ValorNormal;
import desarrollosoft.ghce.servicio.interfaces.IResultadoOperacion;
import desarrollosoft.ghce.servicio.interfaces.IServicioHistorial;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 *
 * @author ariel
 */
@Service("servicioHistorial")
public class ServicioHistorial implements IServicioHistorial {

    @Autowired
    @Qualifier("elementoDAO")
    private IElementoDAO elementoDAO;
    
    @Autowired
    @Qualifier("gravedadDAO")
    private IGravedadDAO gravedadDAO;
    
    @Autowired
    @Qualifier("diagnosticoDAO")
    private IDiagnosticoDAO diagnosticoDAO;
    
    @Autowired
    @Qualifier("monodrogaDAO")
    private IMonodrogaDAO medicamentoDAO;
    
    @Autowired
    @Qualifier("consultaDAO")
    private IConsultaDAO consultaDAO;
    
    @Autowired
    @Qualifier("tratamientoDAO")
    private ITratamientoDAO tratamientoDAO;
    
    @Autowired
    @Qualifier("profesionalDAO")
    private IProfesionalDAO profesionalDAO;
    
    @Autowired
    @Qualifier("intervencionDAO")
    private IIntervencionDAO intervencionDAO;
    
    @Autowired
    @Qualifier("prestacionDAO")
    private IPrestacionDAO cirugiaDAO;
    
    @Autowired
    @Qualifier("plantillaDAO")
    private IPlantillaDAO plantillaDAO;
    
    @Autowired
    @Qualifier("estudioDAO")
    private IEstudioDAO estudioDAO;
    
    @Autowired
    @Qualifier("resultadoComponenteDAO")
    private IResultadoComponenteDAO resultadoComponenteDAO;
    
    @Autowired
    @Qualifier("valorNormalDAO")
    private IValorNormalDAO valorNormalDAO;
    
    @Autowired
    @Qualifier("imagenDAO")
    private IImagenDAO imagenDAO;
    
    @Override
    public List<Elemento> buscarElementos(Paciente pacienteElegido, String descripcion, Gravedad gravedad) {
        return elementoDAO.buscarElementos(pacienteElegido, descripcion, gravedad);
    }
    
    @Override
    public List<String> obtenerTodasTipificaciones() {
        String tipificaciones[] = {
            "",
            "Consulta",
            "Tratamiento",
            "Intervencion",
            "Estudio"
        };
        
        return Arrays.asList(tipificaciones);
    }
    
    @Override
    public List<Gravedad> obtenerTodasGravedades() {
        return gravedadDAO.obtenerTodasGravedades();
    }

    @Override
    public List<Diagnostico> buscarDiagnostico(String nombre) {
        return diagnosticoDAO.buscarDiagnostico(nombre);
    }

    @Override
    public List<Monodroga> buscarMedicamento(String nombre) {
        return medicamentoDAO.buscarMonodroga(nombre);
    }
    
    @Override
    @Transactional
    public void crearConsulta(Consulta consulta, String nombreUsuarioActual) throws Exception {
        if (!fechasValidas(consulta)) {
            throw new Exception("Asegurese de ingresar las fechas correctamente");
        }
        Profesional profesionalActual = profesionalDAO.buscarPorNombreUsuario(nombreUsuarioActual);
        consulta.setProfesional(profesionalActual);
        consultaDAO.crearConsulta(consulta);
    }

    @Override
    @Transactional
    public void modificarConsulta(Consulta consulta, String nombreUsuarioActual) throws Exception {
        if (!fechasValidas(consulta)) {
            throw new Exception("Asegurese de ingresar las fechas correctamente");
        }
        Profesional profesionalActual = profesionalDAO.buscarPorNombreUsuario(nombreUsuarioActual);
        if (!consulta.getProfesional().equals(profesionalActual)) {
            throw new Exception("Intenta modificar una consulta que no fue creada por usted");
        }
        consultaDAO.modificarConsulta(consulta);
    }

    @Override
    @Transactional
    public void eliminarConsulta(Consulta consulta, String nombreUsuarioActual) throws Exception {
        Profesional profesionalActual = profesionalDAO.buscarPorNombreUsuario(nombreUsuarioActual);
        if (!consulta.getProfesional().equals(profesionalActual)) {
            throw new Exception("Intenta eliminar una consulta que no fue creada por usted");
        }
        consultaDAO.eliminarConsulta(consulta);
    }

    @Override
    @Transactional
    public void crearTratamiento(Tratamiento tratamiento, String nombreUsuarioActual) throws Exception {
        if (!fechasValidas(tratamiento)) {
            throw new Exception("Asegurese de ingresar las fechas correctamente");
        }
        Profesional profesionalActual = profesionalDAO.buscarPorNombreUsuario(nombreUsuarioActual);
        tratamiento.setProfesional(profesionalActual);
        tratamientoDAO.crearTratamiento(tratamiento);
    }

    @Override
    @Transactional
    public void modificarTratamiento(Tratamiento tratamiento, String nombreUsuarioActual) throws Exception {
        if (!fechasValidas(tratamiento)) {
            throw new Exception("Asegurese de ingresar las fechas correctamente");
        }
        Profesional profesionalActual = profesionalDAO.buscarPorNombreUsuario(nombreUsuarioActual);
        if (!tratamiento.getProfesional().equals(profesionalActual)) {
            throw new Exception("Intenta modificar un tratamiento que no fue creado por usted");
        }
        tratamientoDAO.modificarTratamiento(tratamiento);
    }

    @Override
    @Transactional
    public void eliminarTratamiento(Tratamiento tratamiento, String nombreUsuarioActual) throws Exception {
        Profesional profesionalActual = profesionalDAO.buscarPorNombreUsuario(nombreUsuarioActual);
        if (!tratamiento.getProfesional().equals(profesionalActual)) {
            throw new Exception("Intenta eliminar un tratamiento que no fue creado por usted");
        }
        tratamientoDAO.eliminarTratamiento(tratamiento);
    }
    
    private boolean fechasValidas(Elemento elemento) throws Exception {
        Date fechaInicio = elemento.getFecha();
        Date fechaFin = elemento.getFechaFin();
        
        if (fechaInicio == null) {
            return true;
        }
        
        Date fechaNacimiento = elemento.getPaciente().getFechaNacimiento();
        if (fechaInicio.before(fechaNacimiento)) {
            throw new Exception("La fecha de inicio no puede ser anterior a la fecha de nacimiento del paciente");
        }
        
        if (fechaFin != null) {
            if (fechaInicio.equals(fechaFin)) {
                return true;
            }
            if (fechaInicio.before(fechaFin)) {
                return true;
            } else {
                return false;
            }
        }
        return true;
    }

    @Override
    @Transactional
    public void crearIntervencion(Intervencion intervencion, String nombreUsuarioActual) throws Exception {
        if (!fechasValidas(intervencion)) {
            throw new Exception("Asegurese de ingresar las fechas correctamente");
        }
        Profesional profesionalActual = profesionalDAO.buscarPorNombreUsuario(nombreUsuarioActual);
        intervencion.setProfesional(profesionalActual);
        intervencionDAO.crearIntervencion(intervencion);
    }

    @Override
    @Transactional
    public void modificarIntervencion(Intervencion intervencion, String nombreUsuarioActual) throws Exception {
        if (!fechasValidas(intervencion)) {
            throw new Exception("Asegurese de ingresar las fechas correctamente");
        }
        Profesional profesionalActual = profesionalDAO.buscarPorNombreUsuario(nombreUsuarioActual);
        if (!intervencion.getProfesional().equals(profesionalActual)) {
            throw new Exception("Intenta modificar un tratamiento que no fue creado por usted");
        }
        intervencionDAO.modificarIntervencion(intervencion);
    }

    @Override
    @Transactional
    public void eliminarIntervencion(Intervencion intervencion, String nombreUsuarioActual) throws Exception {
        Profesional profesionalActual = profesionalDAO.buscarPorNombreUsuario(nombreUsuarioActual);
        if (!intervencion.getProfesional().equals(profesionalActual)) {
            throw new Exception("Intenta eliminar un tratamiento que no fue creado por usted");
        }
        intervencionDAO.eliminarIntervencion(intervencion);
    }

    @Override
    public List<Prestacion> buscarCirugias(String nombre) {
        return cirugiaDAO.buscarPrestaciones(nombre);
    }

    @Override
    @Transactional
    public IResultadoOperacion tratarDeCrearEstudios(List<Plantilla> listaPlantillasElegidas, Paciente paciente, String nombreUsuarioActual) throws Exception {
        IResultadoOperacion resultado = new ResultadoOperacion(); // usar inversion dependencia SPRING
        
        Profesional profesionalActual = profesionalDAO.buscarPorNombreUsuario(nombreUsuarioActual);
        
        for (Plantilla plantillaElegida : listaPlantillasElegidas) {
            Estudio ultimo = estudioDAO.obtenerMasReciente(plantillaElegida, paciente);
            if (ultimo == null) { // si nunca han pedido uno de ese tipo
                estudioDAO.pedir(plantillaElegida, paciente, profesionalActual);
                resultado.agregarComoCorrecto(plantillaElegida);
            } else { // ya le han pedido un estudio igual
                if (estudioDAO.estaTerminado(ultimo)) {
                    estudioDAO.pedir(plantillaElegida, paciente, profesionalActual);
                    resultado.agregarComoCorrecto(plantillaElegida);
                } else {
                    resultado.agregarParaConfirmacion(plantillaElegida);
                }
            }
        }
        return resultado;
    }

    @Override
    @Transactional
    public void crearEstudios(List<Plantilla> listaPlantillas, Paciente paciente, String nombreUsuarioActual) throws Exception {
        Profesional profesionalActual = profesionalDAO.buscarPorNombreUsuario(nombreUsuarioActual);
        for (Plantilla plantilla : listaPlantillas) {
            estudioDAO.pedir(plantilla, paciente, profesionalActual);
        }
    }
    
    @Override
    public Date obtenerFechaUltimoPedidoEstudio(Plantilla plantilla, Paciente paciente) {
        Estudio ultimo = estudioDAO.obtenerMasReciente(plantilla, paciente);
        return ultimo.getFecha();
    }
    
    @Override
    public List<Plantilla> traerTodasPlantillas() {
        return plantillaDAO.traerTodos();
    }

    @Override
    public List<Plantilla> traerTodasPlantillas(String textoBuscar) {
        return plantillaDAO.traerTodos(textoBuscar);
    }

    @Override
    public List<ResultadoComponente> traerResultados(EstudioLaboratorio estudioLaboratorio) {
        return resultadoComponenteDAO.traerResultados(estudioLaboratorio);
    }

    @Override
    @Transactional
    public void guardarResultados(EstudioLaboratorio estudioLaboratorio, List<ResultadoComponente> listaResultadoComponentes, String nombreUsuarioActual) throws Exception {
        // obtener el profesional y checkearlo con el estudio laboratorio
        Profesional profesionalActual = profesionalDAO.buscarPorNombreUsuario(nombreUsuarioActual);
        if (estudioLaboratorio.getProfesionalQueLoCompleto() == null) {
            estudioLaboratorio.setProfesionalQueLoCompleto(profesionalActual);
        } else if (!estudioLaboratorio.getProfesionalQueLoCompleto().equals(profesionalActual)) {
            throw new Exception("No puede modificar este estudio porque usted no lo completo");
        }
        resultadoComponenteDAO.guardarResultados(listaResultadoComponentes);
        estudioDAO.modificar(estudioLaboratorio);
    }

    @Override
    public ValorNormal elegirValorNormal(Componente componente, Paciente paciente) {
        return valorNormalDAO.buscarValorNormal(componente, paciente.getEdad(), paciente.getSexo());
    }

    @Override
    @Transactional
    public void modificarEstudioImaginologia(EstudioImaginologia estudioImaginologia, List<Imagen> listaImagenes, String nombreUsuarioActual) throws Exception {
        if (listaImagenes.isEmpty()) {
            throw new Exception("Recuerde cargar al menos una imagen para el estudio");
        }
        Profesional profesionalActual = profesionalDAO.buscarPorNombreUsuario(nombreUsuarioActual);
        if (estudioImaginologia.getProfesionalQueLoCompleto() == null) { // si no ha sido completado
            if (!listaImagenes.isEmpty()) { // si la lista no es vacia
                estudioImaginologia.setProfesionalQueLoCompleto(profesionalActual); // seteo como que lo completo el actual
            }
        } else if (!estudioImaginologia.getProfesionalQueLoCompleto().equals(profesionalActual)) {
            throw new Exception("No puede modificar este estudio porque usted no lo completo");
        }
        
        if (estudioImaginologia.getArchivoInforme()== null && estudioImaginologia.getInforme() == null) {
            throw new Exception("Recuerde ingresar un informe textual o un archivo de informe");
        }
        /* si esta completo y fechaFin == null, fecha fin seteada como new Date() */
        int cantidadMinimaImagenes = estudioImaginologia.getPlantillaEstudioImagenes().getCantidadMinimaImagenes();
        int cantidadActualImagenes = listaImagenes.size();
        if (estudioImaginologia.getFechaFin() == null && cantidadActualImagenes >= cantidadMinimaImagenes) {
            estudioImaginologia.setFechaFin(new Date());
        }
        
        imagenDAO.modificarOpersistir(listaImagenes, estudioImaginologia);
        estudioDAO.modificarEstudioImaginologia(estudioImaginologia);
    }

    @Override
    public List<String> obtenerTodosTiposEstudios() {
        String tiposEstudios[] = {
            "Estudio Laboratorio",
            "Estudio Imaginologia"
        };
        return Arrays.asList(tiposEstudios);
    }

    @Override
    @Transactional
    public void eliminarEstudioLaboratorio(EstudioLaboratorio estudioLaboratorio, String nombreUsuarioActual) throws Exception {
        Profesional profesionalActual = profesionalDAO.buscarPorNombreUsuario(nombreUsuarioActual);
        if (!estudioLaboratorio.getProfesional().equals(profesionalActual)) {
            throw new Exception("No puede eliminar el Estudio de Laboratorio porque usted no es el profesional que lo solicitó");
        }
        estudioDAO.eliminar(estudioLaboratorio);
    }

    @Override
    @Transactional
    public void eliminarEstudioImaginologia(EstudioImaginologia estudioImaginologia, String nombreUsuarioActual) throws Exception {
        Profesional profesionalActual = profesionalDAO.buscarPorNombreUsuario(nombreUsuarioActual);
        if (!estudioImaginologia.getProfesional().equals(profesionalActual)) {
            throw new Exception("No puede eliminar el Estudio de Laboratorio porque usted no es el profesional que lo solicitó");
        }
        estudioDAO.eliminar(estudioImaginologia);
    }
    
}
